namespace GameNesSL.Cache
{
    using System;
    using System.IO;
    using System.IO.IsolatedStorage;
    using ICSharpCode.SharpZipLib.Zip.Compression.Streams;

    public class Cache
    {
        public static byte[] GetTrueMemoryBuffer(MemoryStream stream)
        {
            byte[] filledBuffer = new byte[stream.Length];
            Array.Copy(stream.GetBuffer(), filledBuffer, (int)stream.Length);
            return filledBuffer;
        }

        public static byte[] Pack(byte[] buffer)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                using (DeflaterOutputStream ouput = new DeflaterOutputStream(ms))
                {
                    ouput.Write(buffer, 0, buffer.Length);
                    ouput.Flush();
                    ouput.Finish();
                    return GetTrueMemoryBuffer(ms);
                }
            }
        }

        public static byte[] Unpack(Stream bytes)
        {
            using (InflaterInputStream stream = new InflaterInputStream(bytes))
            {
                using (MemoryStream memory = new MemoryStream())
                {
                    byte[] writeData = new byte[4096];

                    while (true)
                    {
                        int size = stream.Read(writeData, 0, writeData.Length);
                        if (size > 0)
                        {
                            memory.Write(writeData, 0, size);
                        }
                        else
                            break;
                    }
                    stream.Close();
                    return GetTrueMemoryBuffer(memory);
                }
            }
        }

        public static byte[] Unpack(byte[] bytes)
        {
            return Unpack(new MemoryStream(bytes));
        }

        public static bool IsInCache(string key)
        {
            try
            {
                IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication();
                return file.FileExists(key);
            }
            catch
            {
                return false;
            }
        }

        public static void PutCache(string key, byte[] buffer)
        {
            //Pack
            try
            {

                byte[] packed = Pack(buffer);
                IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication();
                if (CheckAvailibleSpace(key, packed.Length))
                {
                    //Check max
                    using (IsolatedStorageFileStream fs = file.OpenFile(key, FileMode.Create, FileAccess.Write))
                    {
                        fs.Write(packed, 0, packed.Length);
                    }
                }
            }
            catch (Exception)
            {

            }

        }

        public static byte[] GetCache(string key)
        {
            //Pack
            try
            {
                if (IsInCache(key))
                {
                    IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication();
                    //Check max
                    using (IsolatedStorageFileStream fs = file.OpenFile(key, FileMode.Open, FileAccess.Read))
                    {
                        using (BinaryReader br = new BinaryReader(fs))
                        {
                            byte[] packed = br.ReadBytes((int)fs.Length);
                            return Unpack(packed);
                        }
                    }
                }
            }
            catch (Exception)
            {

            }
            return null;

        }

        private static bool CheckAvailibleSpace(string key, int length)
        {
            IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication();
            if (file.AvailableFreeSpace < length)
            {
                //Ask quota
                return file.IncreaseQuotaTo((length - file.AvailableFreeSpace) + file.Quota);
            }
            return true;
        }
    }
}